Skip to content

fix(ColumnLayer): closed shapes with binary data and transition props#10094

Open
charlieforward9 wants to merge 1 commit intovisgl:masterfrom
NEW-HEAT:fix/column-geometry
Open

fix(ColumnLayer): closed shapes with binary data and transition props#10094
charlieforward9 wants to merge 1 commit intovisgl:masterfrom
NEW-HEAT:fix/column-geometry

Conversation

@charlieforward9
Copy link
Copy Markdown
Collaborator

@charlieforward9 charlieforward9 commented Mar 12, 2026

Closes #9463, #10021

Screen.Recording.2026-04-17.at.6.12.02.PM.mov

Background

When using ColumnLayer with binary data and transition props, column shapes render with missing faces — sides of each column appear open/incomplete.

Root cause

ColumnLayer builds one ColumnGeometry (which carries wireframe indices) and passes it to both fillModel and wireframeModel:

  1. fillModel.setGeometry(geometry) stores the geometry in fillModel._gpuGeometry with indices populated.
  2. When the attribute buffer layout changes — e.g. a binary-data transition or HMR — deck.gl's Layer._setModelAttributes calls model.setBufferLayout(...).
  3. setBufferLayout builds a new vertexArray and re-runs _setGeometryAttributes(this._gpuGeometry), which calls setIndexBuffer(gpuGeometry.indices || null). The wireframe indices get re-attached to the fill model.
  4. The triangle-strip fill is then drawn against wireframe indices and renders with broken sides.

Trace: modules/core/src/lib/layer.ts Layer._setModelAttributes@luma.gl/engine Model.setBufferLayout_setGeometryAttributessetIndexBuffer.

Fix

Give the fill model a separate Geometry with no indices, sharing the POSITION / NORMAL buffers with the wireframe geometry. The fill model's _gpuGeometry.indices is null, so no subsequent setBufferLayout / _setGeometryAttributes pass can re-attach wireframe indices.

This fixes the root cause rather than clearing a leaked index buffer every frame in draw() (addresses @felixpalmer's review feedback on the previous revision).

Change list

  • modules/layers/src/column-layer/column-layer.ts — construct a fill-only Geometry (no indices, topology triangle-strip) in _updateGeometry; drop the setIndexBuffer(null) workaround.
  • modules/aggregation-layers/src/hexagon-layer/hexagon-cell-layer.ts — drop the inline index-buffer reset workaround (resolves the TODO - this should be handled in ColumnLayer?).
  • test/modules/layers/column-layer.spec.ts — regression test that simulates the buffer-layout rebuild (fillModel.setBufferLayout(fillModel.bufferLayout)) and asserts fillModel.vertexArray.indexBuffer stays null.

Branch state

Rebased onto latest master (past v9.3.0-beta.2). Single focused commit. The earlier cross-module TS/build cleanup commit was dropped on rebase — all of those fixes landed on master via #10123, #10141, #10158, and #10201.

Render test golden image

A render test case (column-lnglat-binary-extruded) should be added once the vitest render test migration lands. @chrisgervang — can you help wire up the golden image capture when that's ready?

@charlieforward9 charlieforward9 linked an issue Mar 12, 2026 that may be closed by this pull request
7 tasks
@coveralls
Copy link
Copy Markdown

coveralls commented Mar 12, 2026

Coverage Status

coverage: 91.009% (+0.001%) from 91.008%
when pulling 0a6258c on NEW-HEAT:fix/column-geometry
into e6c96ca on visgl:master.

@charlieforward9 charlieforward9 changed the title fix(ColumnLayer): closed shapes with binary data fix(ColumnLayer): closed shapes with binary data and transition props Mar 13, 2026
@charlieforward9 charlieforward9 linked an issue Mar 13, 2026 that may be closed by this pull request
7 tasks
protected _disableFillIndexBuffer() {
const fillModel = this.state.fillModel!;
if (fillModel.vertexArray.indexBuffer) {
// Geometry indices are only for wireframe. Model rebuilds can reattach them.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feels like a bit of a patch for bad behavior elsewhere... is it not possible to avoid the reattachement when the model is rebuilt?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new approach should be more appropriate

Closes visgl#9463, visgl#10021.

ColumnLayer shares a single ColumnGeometry (which carries wireframe
indices) between the fill and wireframe models. With binary data and
transition props, a buffer-layout rebuild re-applies the gpu geometry
to the fill model's new vertex array, re-attaching the wireframe index
buffer. Triangle-strip fill is then indexed against wireframe indices
and renders with missing faces.

Fix the root cause: give the fill model a separate Geometry with no
indices (sharing POSITION / NORMAL buffers with the wireframe geometry).
The fill model's internal _gpuGeometry.indices is null, so later
setBufferLayout to _setGeometryAttributes calls cannot reattach
wireframe indices to the fill vertex array.

- modules/layers/src/column-layer/column-layer.ts: construct fill-only
  Geometry without indices in _updateGeometry; drop the per-frame
  setIndexBuffer(null) workaround in draw().
- modules/aggregation-layers/src/hexagon-layer/hexagon-cell-layer.ts:
  drop the inline index-buffer reset workaround (no longer needed,
  resolves the existing TODO).
- test/modules/layers/column-layer.spec.ts: regression test asserts
  the fill model's indexBuffer stays null after a setBufferLayout()
  rebuild (the trigger that previously leaked wireframe indices).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] ColumnLayer with binary data: shapes are not closed [Bug] ColumnLayer.transition.getFillColor

3 participants